package ThreadService;

import service.PureLogDb;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;

public class NIOServerService {
    private Selector selector;
    private ServerSocketChannel socketChannel;
    private PureLogDb db;

    public NIOServerService(int port) {
        db = new PureLogDb();
        try {
            selector = Selector.open();
            socketChannel = ServerSocketChannel.open();
            //绑定端口号
            socketChannel.bind(new InetSocketAddress("127.0.0.1", port));
            //设置非阻塞
            socketChannel.configureBlocking(false);
            //注册selector,并说明关注点
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("=======服务器启动。。。。。。");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //监听
    public void listen() {
        //创建selector和channel
        try {
            while (true) {
                selector.select();
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = keys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    if (selectionKey.isAcceptable()) {
                        // 获取到连接
                        SocketChannel sc = socketChannel.accept();
                        sc.configureBlocking(false);
                        sc.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                        // 提示连上了
                        System.out.println(sc.getRemoteAddress() + ":客户端安连上了。。。。");
                    }
                    if (selectionKey.isReadable()) {
                        //用来读取事件
                        read(selectionKey);
                    }
                    iterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    //读取客户端消息
    private void read(SelectionKey selectionKey) {
        SocketChannel channel = null;
        try {
            channel = (SocketChannel) selectionKey.channel();
            ByteBuffer buffer = (ByteBuffer) selectionKey.attachment();
            int count = channel.read(buffer);
            if (count > 0) {
                String msg = new String(buffer.array(), 0, count);
                buffer.clear();
                System.out.println("来自客户端的消息:" + msg);
                String[] msgs = msg.split(" ");
                //判断过来的是 set，delete，get命令，根据不同的命令进行不同的实现
                if ("SET".equals(msgs[0].toUpperCase(Locale.ROOT))) db.putVal(msgs[1], msgs[2]);
                else if ("DELETE".equals(msgs[0].toUpperCase(Locale.ROOT))) db.rmVal(msgs[1]);
                else if ("GET".equals(msgs[0].toUpperCase(Locale.ROOT))) {
                    String value = db.getVal(msgs[1]);
                    sendMsgs(value, channel);
                    System.out.println(value);
                }

            }
        } catch (IOException e) {
            // 如果发生异常 提示说明离线了
            try {
                System.out.println(channel.getRemoteAddress() + "挂了。。。。");
                // 取消注册
                selectionKey.cancel();
                // 关闭通道
                channel.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    //发送消息
    private void sendMsgs(String msg, SocketChannel channel) throws IOException {
        System.out.println("服务器发消息。。。。。");
        ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
        channel.write(byteBuffer);
    }

    //群发送消息
    private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {
        System.out.println("服务器群发消息。。。。。");
        // 进行遍历操作
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey key : keys) {
            // 取出来所有的
            Channel targetChannel = key.channel();
            // 排除自己
            if (targetChannel instanceof SocketChannel && targetChannel != self) {
                sendMsgs(msg, (SocketChannel) targetChannel);
            }

        }
    }

    public static void main(String[] args) {
        NIOServerService nioServerService = new NIOServerService(9999);
        nioServerService.listen();
    }
}
